﻿using System.Collections.Generic;
using System.Security.Cryptography;
using BestHTTP.WebSocket;
using LitJson;
using System;
using System.Text;
using UnityEngine;
using Cysharp.Threading.Tasks;
using Bolai.Event;
public class XunfeiWS
{


    private const string URL = "wss://tts-api.xfyun.cn/v2/tts";
    private const string APPID = "a3f8c77c";
    private const string APISecret = "YWUxOTNjOGY2OWRjZGFmOTk4OGFhZGM1";
    private const string APIKey = "a450fc15724b7da9eee37c1209fc5c97";
    private string signature_origin = string.Empty; //原始签名
    private string signature_sha = string.Empty; //使用hmac-sha256算法加密后的signature
    private string signature = string.Empty; //最终编码后的签名
    private string authorization_origin = string.Empty; //原始鉴权
    private string authorization = string.Empty; //最终编码后的鉴权
    private int audioLength = 0; //语音长度
    private string voicer = "xiaoyan"; //发音人
    private Queue<float> audioQue = new();
    private WebSocket ws;
    public Action<AudioClip> OnSucc;

    public AudioSource source;
    private bool isConn;

    public XunfeiWS()
    {

    }
    private void OnOpen(WebSocket ws)
    {
        Debug.Log("讯飞WebSocket连接成功！");
        isConn = true;
    }

    private void OnError(WebSocket ws, Exception ex)
    {
        isConn = false;
        string sf = string.Format("编码{0},详细信息{1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message);
        Debug.Log("错误编码： " + sf);
    }
    private void OnClosed(WebSocket ws, UInt16 code, string message)
    {
        isConn = false;
        Debug.Log("讯飞WebSocket连接关闭！");

    }

    private void OnBinaryReceived(WebSocket ws, byte[] data)
    {
    }
    private void OnMessage(WebSocket ws, string message)
    {
        JsonData js = JsonMapper.ToObject(message);
        //Debug.Log(message);
        if (js["message"].ToString() == "success")
        {
            if (js["data"] != null)
            {
                if (js["data"]["audio"] != null)
                {
                    float[] fs = bytesToFloat(Convert.FromBase64String(js["data"]["audio"].ToString()));
                    audioLength += fs.Length;
                    foreach (float f in fs)
                    {
                        audioQue.Enqueue(f);
                    }
                    if ((int)js["data"]["status"] == 2) //2为结束标志符
                    {
                        ws.Close();
                        ws = null;
                        // var clip = AudioClip.Create("wav", 16000*60, 1, 16000, false, OnAudioRead); //要生成的音频名称、样本帧数(乘以60代表采样时长为1分钟)、每帧的声道数、剪辑采样频率、音频是否以流格式传输、调用该回调以生成样本数据块
                        var clip = AudioClip.Create("wav", audioLength + 10, 1, 16000, false, OnAudioRead); //要生成的音频名称、样本帧数(乘以60代表采样时长为1分钟)、每帧的声道数、剪辑采样频率、音频是否以流格式传输、调用该回调以生成样本数据块
                                                                                                            // AudioSource.PlayClipAtPoint(clip, Vector3.zero);
                        source.clip = clip;
                        source.loop = false;
                        source.Play();
                        ApiBucket.Game.uevent.Call(EventCode.Voice, clip.length, clip);
                    }
                }
            }
        }
    }
    /// <summary>
    /// 采样回调
    /// </summary>
    /// <param name="data"></param>
    private void OnAudioRead(float[] data)
    {
        for (int i = 0; i < data.Length; i++)
        {
            if (audioQue.Count > 0)
                data[i] = audioQue.Dequeue();
            else
            {
                if (ws == null || !ws.IsOpen)
                    audioLength++;
                data[i] = 0;
            }
        }

    }


    private string GetUrl(string url)
    {
        Uri uri = new Uri(url);
        string date = DateTime.Now.ToString("r"); //官方文档要求时间必须是UTC+0或GMT时区，RFC1123格式(Thu, 01 Aug 2019 01:53:21 GMT)。
        ComposeAuthUrl(uri, date);
        string uriStr = string.Format("{0}?authorization={1}&date={2}&host={3}", uri, authorization, date, uri.Host); //生成最终鉴权
        return uriStr;
    }
    /// <summary>
    /// 组装生成鉴权
    /// </summary>
    private void ComposeAuthUrl(Uri uri, string date)
    {
        signature_origin = string.Format("host: " + uri.Host + "\ndate: " + date + "\nGET " + uri.AbsolutePath + " HTTP/1.1");
        //Debug.Log("signature_origin: " + signature_origin);
        signature_sha = HmacSHA256(signature_origin, APISecret); //使用hmac - sha256算法结合apiSecret对signature_origin签名
        //Debug.Log("signature_sha: " + signature_sha);
        signature = signature_sha;
        //Debug.Log("signature: " + signature);
        string auth = "api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"";
        authorization_origin = string.Format(auth, APIKey, "hmac-sha256", "host date request-line", signature); //参数介绍：APIKey,加密算法名，headers是参与签名的参数(该参数名是固定的"host date request-line")，生成的签名
        //Debug.Log("authorization_origin: " + authorization_origin);
        authorization = ToBase64String(authorization_origin);
        //Debug.Log("authorization: " + authorization);
    }


    /// <summary>
    /// 按照官方API组装传输参数
    /// </summary>
    /// <returns></returns>
    private JsonData CreateJsonData(string msg)
    {
        JsonData requestObj = new JsonData();

        requestObj["common"] = new JsonData();
        JsonData commonJson = new JsonData();
        commonJson["app_id"] = APPID;
        requestObj["common"] = commonJson;

        requestObj["business"] = new JsonData();
        JsonData bussinessJson = new JsonData();
        bussinessJson["aue"] = "raw";
        bussinessJson["vcn"] = voicer;
        bussinessJson["pitch"] = 50;
        bussinessJson["speed"] = 50;
        bussinessJson["tte"] = "UTF8";
        requestObj["business"] = bussinessJson;

        requestObj["data"] = new JsonData();
        JsonData dataJson = new JsonData();
        dataJson["status"] = 2;
        dataJson["text"] = ToBase64String(msg);
        requestObj["data"] = dataJson;
        return requestObj;
    }

    //加密算法HmacSHA256  
    private string HmacSHA256(string secret, string signKey)
    {
        string signRet = string.Empty;
        using (HMACSHA256 mac = new HMACSHA256(Encoding.UTF8.GetBytes(signKey)))
        {
            byte[] hash = mac.ComputeHash(Encoding.UTF8.GetBytes(secret));
            signRet = Convert.ToBase64String(hash);
        }
        return signRet;
    }


    //byte[]转16进制格式string
    private string ToHexString(byte[] bytes)
    {
        string hexString = string.Empty;
        if (bytes != null)
        {
            StringBuilder strB = new StringBuilder();
            foreach (byte b in bytes)
            {
                strB.AppendFormat("{0:x2}", b);
            }
            hexString = strB.ToString();
        }
        return hexString;
    }

    ///编码
    private string EncodeBase64(string code_type, string code)
    {
        string encode = "";
        byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code);
        try
        {
            encode = Convert.ToBase64String(bytes);
        }
        catch
        {
            encode = code;
        }
        return encode;
    }

    private string ToBase64String(string value)
    {
        if (value == null || value == "")
        {
            return "";
        }
        byte[] bytes = Encoding.UTF8.GetBytes(value);
        return Convert.ToBase64String(bytes);
    }

    /// <summary>
    /// byte[]数组转化为AudioClip可读取的float[]类型
    /// </summary>
    /// <param name="byteArray"></param>
    /// <returns></returns>
    private float[] bytesToFloat(byte[] byteArray)
    {
        float[] sounddata = new float[byteArray.Length / 2];
        for (int i = 0; i < sounddata.Length; i++)
        {
            sounddata[i] = bytesToFloat(byteArray[i * 2], byteArray[i * 2 + 1]);
        }
        return sounddata;
    }
    private float bytesToFloat(byte firstByte, byte secondByte)
    {
        // convert two bytes to one short (little endian)
        //小端和大端顺序要调整
        short s;
        if (BitConverter.IsLittleEndian)
            s = (short)((secondByte << 8) | firstByte);
        else
            s = (short)((firstByte << 8) | secondByte);
        // convert to range from -1 to (just below) 1
        return s / 32768.0F;
    }


    public async void SendMessage(string msg, int sex)
    {
        voicer = sex == 1 ? "aisjiuxu" : "voicer";


        if (ws != null && ws.IsOpen)
        {
            ws.Close();
        }
        audioLength = 0;
        audioQue.Clear();
        ws = new WebSocket(new System.Uri(GetUrl(URL)));
        ws.OnOpen += OnOpen;
        ws.OnBinary += OnBinaryReceived;
        ws.OnMessage += OnMessage;
        ws.OnError += OnError;
        ws.OnClosed += OnClosed;
        ws.Open();

        await UniTask.WaitUntil(() => ws.IsOpen);
        JsonData jsonData = CreateJsonData(msg);
        ws.Send(JsonMapper.ToJson(jsonData));
    }
    public void Close()
    {
        if (source) source.Stop();
        if (ws != null && ws.IsOpen)
        {
            ws.Close();
        }
    }

    public enum Sounds
    {
        //女-晓璇
        x4_xiaoxuan,
        //女-小露
        x4_yezi,
        //男-飞晨
        x4_lingfeichen_assist,
        //男-一峰
        x4_lingfeng

    }
}
